<?php

namespace july\julyadmin\builder\table;

use july\julyadmin\builder\FormBase;
use july\julyadmin\builder\table\JsTree;
use july\julyadmin\builder\table\Search;
use july\julyadmin\builder\table\Toolbar;

/**
 * 表单layui表格组件
 */
class DataTable extends FormBase
{
    /**
     * 添加组件
     * @param  class  $parent     上级对象
     * @param  string $field      字段
     * @return this
     */
    public function __construct($parent, $field = '')
    {
        $form        = new \stdClass();
        $form->type  = 'layui-data-table';
        $form->field = $field;
        //第几页
        $form->page = 1;
        //每页多少条
        $form->rows = 20;
        //总共多少条
        $form->total = 0;
        //表单提交过来的查询信息
        $form->search = [];
        //工具栏
        $form->toolbar = [];
        //ajax请求地址
        $form->datagridUrl = '';
        //table高度
        $form->height = '';
        //是否显示页脚
        $form->showFooter = false;
        //表格id
        $form->tableId = '';
        //表格行按钮
        $form->tableRowBtns = [];
        //上级类
        $form->parent = $parent;
        //数据表字段列表
        $form->cols = [];
        //分页条数列表
        $form->limits = [20, 50, 80, 100, 200];
        //是否显示分页
        $form->showPage = true;
        //连续页码数
        $form->groups = 2;
        //是否显示多选框
        $form->showCheckbox = false;
        //是否开启合计行
        $form->showTotalRow = false;
        //字段组如果要合并表格表头，就必须大于1
        $form->colsIndex = 1;
        //表格标题
        $form->tableTitle = '';
        //是否自动换行
        $form->autoWrap = true;
        //表格类型
        $form->tableType = 'table';
        //是否显示筛选列按钮
        $form->filterShow = true;
        //是否显示打印按钮
        $form->printShow = true;
        //是否显示导出按钮
        $form->exportShow = true;
        //是否显示导入按钮
        $form->importShow = true;
        //自定义工具栏按钮列表
        $form->customerToolbars = [];
        //行样式，可以设置行高，文字颜色等
        $form->lineStyle = 'auto';
        //是否显示tree图标
        $form->showIcon = true;
        //是否显示默认工具栏
        $form->showDefaultToolbar = true;
        //是否默认展开
        $form->expandAllDefault = 'true';
        //自定义格式内容
        $form->to = [];
        //树形表格分组字段，比如name，那么展开和搜索箭头就会在name这一列显示
        $form->treeTableGroupField = 'name';
        //开关开启和关闭的文字
        $form->switchBtnText = ['开启', '关闭'];
        //左边树形列表
        $form->leftTree = null;
        $this->form     = $form;
        return $this;
    }

    /**
     * 设置属性表格分组字段
     * @Author   july
     * @DateTime 2023-09-06
     * @param    string     $field 字段名称
     */
    public function treeTableGroupField($field = '')
    {
        $this->form->treeTableGroupField = $field;
        return $this;
    }

    /**
     * 设置表格类型
     * @param string $type 表格类型table,treeTable
     * @return  this
     */
    public function tableType($type = 'table')
    {
        $this->form->tableType = $type;
        return $this;
    }

    /**
     * 设置行样式
     * @param string $style 样式height:97px;color:red;
     */
    public function lineStyle($style = '')
    {
        $this->form->lineStyle = $style;
        return $this;
    }

    /**
     * 是否显示节点图标
     * @param    boolean                  $show 是否显示节点图标
     * @return   this
     */
    public function showIcon($show = true)
    {
        $this->form->showIcon = $show;
        return $this;
    }

    /**
     * 设置table高度
     * @param string $height 高度
     * @return  this
     */
    public function tableHeight($height = '')
    {
        $this->form->height = $height;
        return $this;
    }

    /**
     * 是否显示默认工具栏
     * @param  boolean $show 是否显示
     * @return this
     */
    public function showDefaultToolbar($show = true)
    {
        $this->form->showDefaultToolbar = $show;
        return $this;
    }

    /**
     * 设置是否默认展开
     * @Author
     * @DateTime 2023-06-22T00:04:20+0800
     * @param    boolean                  $expandAllDefault 是否默认展开
     */
    public function expandAllDefault($expandAllDefault = true)
    {
        $this->form->expandAllDefault = $expandAllDefault ? 'true' : 'false';
        return $this;
    }

    /**
     * 添加工具栏按钮
     * [
     *    'title'    => '导出xls',//按钮标题
     *    'layEvent' => 'EXPORT_XLS',//按钮事件名称
     *    'icon'     => 'layui-icon-export',//按钮图标,layui的图标
     *    'function' => 'alert("asdfasdf")'//执行js
     * ]
     * @param array $toolbar 工具栏按钮
     */
    public function addToolbar($toolbar = [])
    {
        $tips = <<<EOT

[
    'title'    => '导出xls',//按钮标题
    'layEvent' => 'EXPORT_XLS',//按钮事件名称
    'icon'     => 'layui-icon-export',//按钮图标,layui的图标
    'function' => 'alert("asdfasdf")'//执行js
]

EOT;
        if (!isset($toolbar['title']) || !is_string($toolbar['title'])) {
            throw new \Exception("工具栏按钮格式：" . $tips);
        }

        if (!isset($toolbar['layEvent']) || !$toolbar['layEvent'] || !is_string($toolbar['layEvent'])) {
            throw new \Exception("工具栏按钮格式：" . $tips);
        }

        if (!isset($toolbar['icon']) || !$toolbar['icon'] || !is_string($toolbar['icon'])) {
            throw new \Exception("工具栏按钮格式：" . $tips);
        }

        if (!isset($toolbar['function']) || !is_string($toolbar['function'])) {
            throw new \Exception("工具栏按钮格式：" . $tips);
        }

        $toolbar['function'] = str_replace(PHP_EOL, '', $toolbar['function']);

        $this->form->customerToolbars[] = $toolbar;
        return $this;
    }

    /**
     * 设置显示筛选字段按钮
     * @param boolean $show 是否显示
     * @return  this
     */
    public function filterShow($show = true)
    {
        $this->form->filterShow = $show;
        return $this;
    }

    /**
     * 设置显示打印按钮
     * @param boolean $show 是否显示
     * @return  this
     */
    public function printShow($show = true)
    {
        $this->form->printShow = $show;
        return $this;
    }

    /**
     * 设置显示导出xls按钮
     * @param boolean $show 是否显示
     * @return  this
     */
    public function exportShow($show = true)
    {
        $this->form->exportShow = $show;
        return $this;
    }

    /**
     * 设置显示导入按钮
     * @Author   July
     * @DateTime 2023-10-13T21:15:02+0800
     * @param    boolean                  $show 是否显示
     * @return this
     */
    public function importShow($show = true)
    {
        $this->form->importShow = $show;
        return $this;
    }

    /**
     * 设置自动换行
     * @param boolean $autoWrap 是否自动换行
     * @return  this
     */
    public function autowrap($autoWrap = true)
    {
        $this->form->autoWrap = $autoWrap;
        return $this;
    }

    /**
     * 设置分页条数列表
     * @param   array $limits 分页条数列表
     * @return  this
     */
    public function limits($limits = [])
    {
        $this->form->limits = $limits;
        return $this;
    }

    /**
     * 设置表格标题
     * @param   string $title 表格标题
     * @return  this
     */
    public function tableTitle($title = '')
    {
        $this->form->tableTitle = $title;
        return $this;
    }

    /**
     * 设置tableid
     * @param string $tableId tableID
     * @return  this
     */
    public function tableId($tableId)
    {
        $this->form->tableId = $tableId;
        return $this;
    }

    /**
     * 设置表格请求url
     * @param string $url 请求url
     * @return  this
     */
    public function datagridUrl($url)
    {
        $this->form->datagridUrl = $url;
        return $this;
    }

    /**
     * 获取工具栏
     * @return  toolbar
     */
    public function getToolbar()
    {
        $this->form->toolbar[] = (new Toolbar($this->form->parent, 'toolbar', $this->form->parent->pk))
            ->bindTableId($this->form->tableId)
            ->tableType($this->form->tableType);
        return $this->form->toolbar[count($this->form->toolbar) - 1];
    }

    /**
     * 获取表格行按钮对象
     * @return  toolbar
     */
    public function getTableRowBtns()
    {
        $this->form->tableRowBtns[] = (new Toolbar($this->form->parent, 'tablerow', $this->form->parent->pk))
            ->bindTableId($this->form->tableId)
            ->tableType($this->form->tableType);
        return $this->form->tableRowBtns[count($this->form->tableRowBtns) - 1];
    }

    /**
     * 表格列显示
     * @param  string $field      字段
     * @param  string $title      字段名称
     * @param  string $form_type  组件类型：image,switchBtn或者留空
     * @return this
     */
    public function show($field, $title, $form_type = '')
    {
        $col                = new \stdClass();
        $col->field         = $field;
        $col->title         = $title;
        $col->form_type     = $form_type;
        $col->switchBtnText = $this->form->switchBtnText;
        $col->templet       = urlencode("return val;");
        if ($form_type == 'image') {
            $col->thumbWidth  = 45;
            $col->thumbHeight = 45;
        }
        $this->form->cols[$this->form->colsIndex - 1][] = $col;
        return $this;
    }

    /**
     * 表格编辑
     * @Author   july
     * @DateTime 2023-09-05
     * @param  string $editType  编辑状态类型：text,number,date,datetime-local,month,time,color,email,week,switchBtn
     * @return this
     */
    public function edit($editType = '')
    {
        $col = $this->form->cols[$this->form->colsIndex - 1][count($this->form->cols[$this->form->colsIndex - 1]) - 1];
        if ($editType) {
            $col->editType = $editType;
        }
        if ($editType == 'checkbox') {
            $col->options = [];
        }
        if ($editType && $editType != 'image') {
            $url = url(request()->controller() . "/autopost");
        }
        $this->form->cols[$this->form->colsIndex - 1][count($this->form->cols[$this->form->colsIndex - 1]) - 1] = $col;
        return $this;
    }

    /**
     * 设置select 数据
     * @param  array $options 下拉数据，键值对数组
     * @return this
     */
    public function options($options = [])
    {

        if (in_array($this->form->cols[$this->form->colsIndex - 1][count($this->form->cols[$this->form->colsIndex - 1]) - 1]->editType, ["checkbox", "radio"])) {
            $this->form->cols[$this->form->colsIndex - 1][count($this->form->cols[$this->form->colsIndex - 1]) - 1]->options = $options;
        } else {
            throw new \Exception("组件：" . $this->form->cols[$this->form->colsIndex - 1][count($this->form->cols[$this->form->colsIndex - 1]) - 1]->editType . "不支持此方法！");
        }
        return $this;
    }

    /**
     * 设置是否显示分页
     * @Author   July
     * @DateTime 2024-01-15T19:33:41+0800
     * @param    boolean                  $showPage 是否显示分页
     * @return   this
     */
    public function showPage($showPage = true)
    {
        $this->form->showPage = $showPage;
        return $this;
    }

    /**
     * 设置连续页码数
     * @Author   July
     * @DateTime 2024-01-15T19:33:03+0800
     * @param    integer                  $groups 连续页码数
     * @return   this
     */
    public function groups($groups = 2)
    {
        $this->form->groups = $groups;
        return $this;
    }

    /**
     * 是否显示行复选框
     * @param  $show  true,false
     * @return this
     */
    public function showCheckbox($show = true)
    {
        $this->form->showCheckbox = $show;
        return $this;
    }

    /**
     * 设置列宽度
     * @param string $width 字段宽度
     * @return this
     */
    public function width($width = "")
    {
        if ($this->form->cols) {
            $this->form->cols[$this->form->colsIndex - 1][count($this->form->cols[$this->form->colsIndex - 1]) - 1]->width = $width;
        }
        return $this;
    }

    /**
     * 设置缩略图宽高
     * @param  string $width  宽度 如：60px
     * @param  string $height 高度 如：60px
     * @return this
     */
    public function thumbSize($width = "", $height = "")
    {
        if (!isset($this->form->cols[$this->form->colsIndex - 1][count($this->form->cols[$this->form->colsIndex - 1]) - 1]->editType)) {
            throw new \Exception("请先调用：->edit('image')设置编辑类型为image，随后才能调用thumbSize()！");
        }
        if (in_array($this->form->cols[$this->form->colsIndex - 1][count($this->form->cols[$this->form->colsIndex - 1]) - 1]->editType, ["image"])) {
            $this->form->cols[$this->form->colsIndex - 1][count($this->form->cols[$this->form->colsIndex - 1]) - 1]->thumbWidth  = $width;
            $this->form->cols[$this->form->colsIndex - 1][count($this->form->cols[$this->form->colsIndex - 1]) - 1]->thumbHeight = $height;

        } else {
            throw new \Exception("组件：" . $this->form->cols[$this->form->colsIndex - 1][count($this->form->cols[$this->form->colsIndex - 1]) - 1]->editType . "不支持此方法！");
        }
        return $this;
    }

    /**
     * 设置列宽度最小宽度
     * @param string $minWidth 字段最小宽度
     * @return this
     */
    public function minWidth($minWidth = "")
    {
        if ($this->form->cols) {
            $this->form->cols[$this->form->colsIndex - 1][count($this->form->cols[$this->form->colsIndex - 1]) - 1]->minWidth = $minWidth;
        }
        return $this;
    }

    /**
     * 设置列类型
     * @param string $type 字段类型
     * @return this
     */
    public function setType($type = "")
    {
        if ($this->form->cols) {
            $this->form->cols[$this->form->colsIndex - 1][count($this->form->cols[$this->form->colsIndex - 1]) - 1]->type = $type;
        }
        return $this;
    }

    /**
     * 设置列浮动
     * @param string $fixed 字段浮动，left/right
     * @return this
     */
    public function fixed($fixed = "")
    {
        if ($this->form->cols) {
            $this->form->cols[$this->form->colsIndex - 1][count($this->form->cols[$this->form->colsIndex - 1]) - 1]->fixed = $fixed;
        }
        return $this;
    }

    /**
     * 设置列显示隐藏
     * @param boolean $hide true,false
     * @return this
     */
    public function hide($hide = false)
    {
        if ($this->form->cols) {
            $this->form->cols[$this->form->colsIndex - 1][count($this->form->cols[$this->form->colsIndex - 1]) - 1]->hide = $hide;
        }
        return $this;
    }

    /**
     * 设置是否开启合计行
     * @param boolean $show true,false
     * @return this
     */
    public function totalRow($show = false)
    {
        $this->form->showTotalRow = $show;
        return $this;
    }

    /**
     * 设置列合计开启关闭和显示
     * @param boolean $totalRow true,false,string
     * @return this
     */
    public function colTotalRow($totalRow = false)
    {
        if ($this->form->cols) {
            $this->form->cols[$this->form->colsIndex - 1][count($this->form->cols[$this->form->colsIndex - 1]) - 1]->totalRow = $totalRow;
        }
        return $this;
    }

    /**
     * 设置列合计文本
     * @param string $text string，如"合计："
     * @return this
     */
    public function colTotalRowText($text = "")
    {
        if ($this->form->cols) {
            $this->form->cols[$this->form->colsIndex - 1][count($this->form->cols[$this->form->colsIndex - 1]) - 1]->totalRowText = $text;
        }
        return $this;
    }

    /**
     * 设置列是否排序
     * @param boolean $is_sort true,false
     * @return this
     */
    public function sort($is_sort = false)
    {
        if ($this->form->cols) {
            $this->form->cols[$this->form->colsIndex - 1][count($this->form->cols[$this->form->colsIndex - 1]) - 1]->sort = $is_sort;
        }
        return $this;
    }

    /**
     * 是否禁用拖拽列宽（默认：false）。默认情况下会根据列类型（type）来决定是否禁用，如复选框列，会自动禁用。而其它普通列，默认允许拖拽列宽，当然你也可以设置 true 来禁用该功能。
     * @param boolean $unresize [description]
     * @return this
     */
    public function unresize($unresize = false)
    {
        if ($this->form->cols) {
            $this->form->cols[$this->form->colsIndex - 1][count($this->form->cols[$this->form->colsIndex - 1]) - 1]->unresize = $unresize;
        }
        return $this;
    }

    /**
     * 自定义单元格点击事件名，以便在 tool 事件中完成对该单元格的业务处理
     * @param string $event
     * @return this
     */
    public function event($event = "")
    {
        if ($this->form->cols) {
            $this->form->cols[$this->form->colsIndex - 1][count($this->form->cols[$this->form->colsIndex - 1]) - 1]->event = $event;
        }
        return $this;
    }

    /**
     * 设置单元格样式，直接传入css
     * @param string $style background-color: #5FB878; color: #fff;
     * @return this
     */
    public function style($style = "")
    {
        if ($this->form->cols) {
            $this->form->cols[$this->form->colsIndex - 1][count($this->form->cols[$this->form->colsIndex - 1]) - 1]->style = $style;
        }
        return $this;
    }

    /**
     * 设置单元格排列方式
     * @param string $align 可选值有：left（默认）、center（居中）、right（居右）
     * @return this
     */
    public function align($align = 'center')
    {
        if ($this->form->cols) {
            $this->form->cols[$this->form->colsIndex - 1][count($this->form->cols[$this->form->colsIndex - 1]) - 1]->align = $align;
        }
        return $this;
    }

    /**
     * 设置列索引
     * @param integer $val 组索引
     * @return this
     */
    public function colsIndex($val = 1)
    {
        if ($val <= 0) {
            throw new \Exception("colsIndex最小为1");
        }
        $this->form->colsIndex = $val;
        return $this;
    }

    /**
     * 设置单元格所占列数,一般用于多级表头，必须配合colsIndex使用
     * @param integer $colspan 列数
     * @return this
     */
    public function colspan($colspan = 1)
    {
        if ($this->form->cols) {
            $this->form->cols[$this->form->colsIndex - 1][count($this->form->cols[$this->form->colsIndex - 1]) - 1]->colspan = $colspan;
            if (isset($this->form->cols[$this->form->colsIndex - 1][count($this->form->cols[$this->form->colsIndex - 1]) - 1]->field)) {
                unset($this->form->cols[$this->form->colsIndex - 1][count($this->form->cols[$this->form->colsIndex - 1]) - 1]->field);
            }
        }
        return $this;
    }

    /**
     * 设置单元格所占行数,一般用于多级表头，必须配合colsIndex使用
     * @param integer $colspan 行数
     * @return this
     */
    public function rowspan($rowspan = 1)
    {
        if ($this->form->cols) {
            $this->form->cols[$this->form->colsIndex - 1][count($this->form->cols[$this->form->colsIndex - 1]) - 1]->rowspan = $rowspan;
        }
        return $this;
    }

    /**
     * 自定义列模板，模板遵循 laytpl 语法。这是一个非常实用的功能，你可借助它实现逻辑处理，以及将原始数据转化成其它格式，如时间戳转化为日期字符等
     * @param string $templet js字符串
     * 比如 'return "<div style=\'color:red;\'>"+val+"</div>";'
     * 不可有function，在js中可以调用val和row两个变量，，val是当前字段值，row是当前行数据
     * @return this
     */
    public function templet($templet = "")
    {
        if ($this->form->cols) {
            $this->form->cols[$this->form->colsIndex - 1][count($this->form->cols[$this->form->colsIndex - 1]) - 1]->templet = urlencode($templet);
        }
        return $this;
    }

    /**
     * 显示表格行操作按钮
     * @param string $title 表头名称
     * @param string $fixed 浮动方向,left,right
     * @return this
     */
    public function showRowHandleMenus($title = "操作", $fixed = "right")
    {
        $col                                            = new \stdClass();
        $col->fixed                                     = $fixed;
        $col->title                                     = $title;
        $col->templet                                   = '#' . $this->form->tableId . '_row_toolbar';
        $this->form->cols[$this->form->colsIndex - 1][] = $col;
        return $this;
    }

    /**
     * 获取搜索表单
     * @return this
     */
    public function getSearch()
    {
        $this->form->search[] = (new Search())->bindTableId($this->form->tableId);
        return $this->form->search[count($this->form->search) - 1];
    }

    /**
     * 设置每页行数
     * @param integer $rows 行数
     * @return this
     */
    public function rows($rows = 20)
    {
        $this->form->rows = $rows;
        return $this;
    }

    /**
     * 自定义格式内容
     * @Author
     * @DateTime 2023-08-07T21:37:46+0800
     * @param    string                   $value [description]
     * @return   this
     */
    public function to($value = '')
    {
        $field                  = $this->form->cols[count($this->form->cols) - 1][count($this->form->cols[count($this->form->cols) - 1]) - 1]->field;
        $this->form->to[$field] = $value;
        return $this;
    }

    /**
     * 设置开关开启和关闭文字
     * @Author   july
     * @DateTime 2023-09-05
     * @param    array     $val 开启和关闭文字['开启','关闭']
     * @return   this
     */
    public function switchBtnText($val = [])
    {
        if (!$val || !is_array($val) || count($val) < 2) {
            throw new \Exception("switchBtnText格式为：['开启','关闭']，第一个参数为开关开启时的文字，第二个参数为开关关闭时的文字");
        }
        $this->form->switchBtnText = $val;
        return $this;
    }

    /**
     * 是否显示左边树形列表
     * @param  string  $field     左边树形列表字段名称
     * @param  string  $title     左边树形列表标题
     * @return this
     */
    public function showLeftTree($field, $title = '')
    {
        $this->form->leftTree = new JsTree($field, $title);
        $this->form->leftTree->tableType($this->form->tableType)->bindTableId($this->form->tableId);
        return $this->form->leftTree;
    }

    /**
     * 渲染组件
     */
    public function render()
    {
        $input_html     = '';
        $toolbar_script = '';
        $toolbar_html   = '';
        foreach ($this->form->toolbar as $toolbar_k => $toolbar_v) {
            $result = $toolbar_v->render();
            $toolbar_html .= $result['html'];
            $toolbar_script .= $result['script'];
        }
        $this->script .= $toolbar_script;

        $table_row_btns_html   = '';
        $table_row_btns_script = '';
        foreach ($this->form->tableRowBtns as $toolbar_k => $toolbar_v) {
            $result = $toolbar_v->render();
            $table_row_btns_html .= $result['html'];
            $table_row_btns_script .= $result['script'];
        }
        $this->script .= $table_row_btns_script;

        $search_html   = '';
        $search_script = '';
        foreach ($this->form->search as $search_k => $search_v) {
            $result = $search_v->render();
            $search_html .= $result['html'];
            $search_script .= $result['script'];
        }
        $this->script .= $search_script;

        $input_html .= <<<EOT
            <div class="card" style="background:unset;margin-bottom:0px;">
EOT;
        if ($this->form->tableTitle && !$this->form->leftTree) {
            $input_html .= <<<EOT

                    <header class="card-header">
                        <div class="card-title">{$this->form->tableTitle}</div>
                    </header>
EOT;
        }

        if ($this->form->autoWrap) {
            $input_html .= <<<EOT

            <style>
                /*表格改为自动换行*/
                .layui-table-cell{
                    height:auto;
                    overflow:visible;
                    text-overflow:inherit;
                    white-space:normal;
                }
                </style>

EOT;
        }
        $table_content = <<<EOT

                <script type="text/html" id="{$this->form->tableId}_toolbar">
                {$search_html}
                {$toolbar_html}
                </script>
                <script type="text/html" id="{$this->form->tableId}_row_toolbar">
                {$table_row_btns_html}
                </script>
                <table class="layui-hide" id="{$this->form->tableId}" lay-filter="{$this->form->tableId}"></table>

EOT;
        if ($this->form->leftTree) {
            $table_content = $this->renderLeftTree($table_content);
        }
        $input_html .= <<<EOT
                <div class="card-body">
                    {$table_content}
                </div>
            </div>

EOT;

        $showFooter = $this->form->showFooter ? 'true' : 'false';
        $showPage   = $this->form->showPage ? 'true' : 'false';
        $limits     = json_encode($this->form->limits);

        $cols = [];
        //遍历表格列
        foreach ($this->form->cols as $col_group_k => $col_group_v) {
            foreach ($col_group_v as $cols_k => $cols_v) {
                //如果表格列字段是xxx.xxx这种类型，并且没有添加templet，那么就要添加一个，并且return val;下面会有代码替换到一个格式化的方法中去，最终得到xxx.xxx的值
                if ((!isset($cols_v->templet) || $cols_v->templet) && isset($cols_v->field) && strpos($cols_v->field, ".") > -1) {
                    $this->form->cols[$col_group_k][$cols_k]->templet = urlencode("return val;");
                }
            }
        }

        //遍历所有列，重新放到一个新数组中
        foreach ($this->form->cols as $col_group_k => $col_group_v) {
            foreach ($col_group_v as $cols_k => $cols_v) {
                $col = [];
                foreach ($cols_v as $col_k => $col_v) {
                    if (!is_object($col_v)) {
                        $col[$col_k] = $col_v;
                    }
                }

                if ($col) {
                    $cols[$col_group_k][] = $col;
                }
            }
        }

        //是否显示多选
        if ($this->form->showCheckbox) {
            array_unshift($cols[0], ['type' => 'checkbox']);
        }
        //将拼装好的列json_encode
        $cols = json_encode($cols, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES | JSON_NUMERIC_CHECK | JSON_PARTIAL_OUTPUT_ON_ERROR);
        $cols = preg_replace('/:\s*(true|false)/i', ':$1', $cols);

        //字段格式化方法模板
        $templet = '
                        function (row){
                            if(this.field.indexOf(".")>-1){
                                var field = this.field.split(".");
                                var val = row;
                                for(var i=0;i<field.length;i++){
                                    try {
                                        val = val[field[i]];
                                    } catch (e) {
                                        val = "";
                                    }
                                }
                                if(val == null){
                                    val = "";
                                }
                                function templet(val,row){
                                    ___templet_function___
                                };

                                var newVal = templet(val,row);

                            }else{
                                var val = row[this.field];
                                if(val == null){
                                    val = "";
                                }
                                function templet(val,row){
                                    ___templet_function___
                                };
                                var newVal = templet(val,row);

                            }
                            val = templetFormatterInput(val,newVal,row);
                            return val;
                        }';
        //遍历所有列，如果有templet，那么就替换到上面的格式化模板中，然后再把最终的模板数据替换到列的templet属性上面
        foreach ($this->form->cols as $col_group_k => $col_group_v) {
            foreach ($col_group_v as $cols_k => $cols_v) {
                foreach ($cols_v as $col_k => $col_v) {
                    if ($col_k == "templet") {
                        if (isset($cols_v->templet) && isset($cols_v->field)) {
                            $cols = str_replace('"' . $col_v . '"', str_replace("___templet_function___", urldecode($col_v), $templet), $cols);
                        }
                    }
                }
            }
        }

        $autopost_url      = url(request()->controller() . "/autopost");
        $noEditPrimarykeys = json_encode($this->form->parent->noEditPrimarykeys);
        if (!$this->form->height) {
            if ($this->form->leftTree) {
                $this->form->height = "$('body').height()-130";
            } else {
                $this->form->height = "$('body').height()-70";
            }
        } else {
            $this->form->height = "'{$this->form->height}'";
        }

        //设置默认工具栏
        $defaultToolbar = [];
        //筛选列按钮
        if ($this->form->filterShow == true) {
            $defaultToolbar[] = 'filter';
        }

        //打印按钮
        if ($this->form->printShow == true) {
            $defaultToolbar[] = 'print';
        }

        //导出按钮
        if ($this->form->exportShow == true) {
            $defaultToolbar[] = [
                'title'    => '导出',
                'layEvent' => 'EXPORT',
                'icon'     => 'layui-icon-export',
            ];
        }

        //导入按钮
        if ($this->form->importShow == true) {
            $defaultToolbar[] = [
                'title'    => '导入',
                'layEvent' => 'IMPORT',
                'icon'     => 'mdi mdi-database-import',
            ];
        }

        //将用户自己添加到工具栏按钮合并到默认工具栏
        if ($this->form->customerToolbars) {
            $customerToolbars = $this->form->customerToolbars;
            foreach ($customerToolbars as $ctk => $ctv) {
                if (isset($ctv['function'])) {
                    unset($customerToolbars[$ctk]['function']);
                }
            }

            $defaultToolbar = array_merge($customerToolbars, $defaultToolbar);
        }

        if (!$this->form->showDefaultToolbar) {
            $defaultToolbar = [];
        }

        $defaultToolbar = json_encode($defaultToolbar, JSON_UNESCAPED_UNICODE);

        $this->form->showIcon = $this->form->showIcon ? 'true' : 'false';

        $export_url   = url(request()->controller() . "/export");
        $import_url   = url(request()->controller() . "/import");
        $uploadUrl    = url('Files/commonUploadForm');
        $table_md5    = md5($this->form->tableId);
        $showTotalRow = $this->form->showTotalRow ? 'true' : 'false';
        $this->script .= <<<EOT
        <script>
            //更新浮动列高度
            function autoFixedHeight(tableElem) {
                var \$tableView = tableElem || $(".layui-table-view");
                var dataIndex, trHeight;
                \$tableView.each(function() {
                    // 获取两侧浮动栏
                    var \$fixed = $(this).find(".layui-table-fixed");
                    // 同步表头高度
                    \$fixed.find(".layui-table-header tr").height($(this).find(".layui-table-header tr").eq(0).height());
                    // 遍历tr 修正浮动栏行高
                    $(this).find(".layui-table-main tr").each(function() {
                        dataIndex = $(this).attr("data-index");
                        trHeight = $(this).css("height");
                        \$fixed.find("tr[data-index=" + dataIndex + "]").css("height", trHeight);
                        $(this).css("height", trHeight);
                    })
                });
            }
            var self = this;
            var table_self_data_index = '';
            //刷新
            function tableRefresh(){
                layui.{$this->form->tableType}.reloadData('{$this->form->tableId}');
            }
            layui.use('table', function(){
                var table = layui.{$this->form->tableType};
                table.render({
                    elem: '#{$this->form->tableId}',
                    url: '{$this->form->datagridUrl}',
                    height:{$this->form->height},
                    method: 'post',
                    skin:'line',
                    //行样式
                    lineStyle:'{$this->form->lineStyle}',
                    //禁用前端排序
                    autoSort:false,
                    //工具栏
                    toolbar :'#{$this->form->tableId}_toolbar',
                    defaultToolbar: {$defaultToolbar},
                    //开启分页
                    page: {$showPage},
                    //第几页
                    curr: {$this->form->page},
                    //每页多少条
                    limit: {$this->form->rows},
                    //请求数据时显示loading
                    loading: true,
                    //分页条数列表
                    limits: {$limits},
                    //连续页码
                    groups: {$this->form->groups},
                    //开启合计
                    totalRow:{$showTotalRow},
                    //字段数据
                    cols:(function(){
                        var arr = {$cols};
                        // 初始化筛选状态
                        var local = layui.data('{$this->form->tableId}-filter'); // 获取对应的本地记录
                        console.log(local);
                        layui.each(arr, function(index, rows){
                            layui.each(rows,function(findex,fitem){
                                if(fitem.field in local){
                                    fitem.hide = local[fitem.field];
                                }
                            });
                        });
                        return arr;
                    }()),
                    //tree参数
                    tree: {
                        customName: {
                            name:'{$this->form->treeTableGroupField}',
                        },
                        view: {
                            showIcon:{$this->form->showIcon},
                            iconLeaf:'',
                            //默认展开
                            expandAllDefault:{$this->form->expandAllDefault}
                        }
                    },
                    done: function (res, curr, count) {
                        // 记录筛选状态
                        var that = this;
                        that.elem.next().on('mousedown', 'input[lay-filter="LAY_TABLE_TOOL_COLS"]+', function(){
                            var input = $(this).prev()[0];
                            // 此处表名可任意定义
                            layui.data('{$this->form->tableId}-filter', {
                              key: input.name
                              ,value: input.checked
                            })
                        });

                        setTimeout(function(){
                            $('.layui-table tbody tr').each(function(a,b){
                                $(b).find("td").eq($(b).find("td").length-1).css({width:'100%'});
                            });
                            // $('.layui-table-col-special').css({width:'100%'});
                        },100);

                        // 接入图片查看插件
                        setTimeout(function(){
                            $('.preview-img').each(function() {
                                $(this).click(function(){
                                    var url = $(this).attr('src');
                                    //判断图片是否有效
                                    $.ajax({
                                        url: url,
                                        type: 'HEAD',
                                        async: false,
                                        success: function (data, textStatus, xhr) {
                                            var contentType = xhr.getResponseHeader('Content-Type');
                                            if (contentType && contentType.indexOf('image/') === 0) {
                                                //如果资源有效，并且类型是图片，那么弹窗预览
                                                layer.photos({
                                                    photos: {
                                                        "title": "图片查看",
                                                        "start": 0,
                                                        "data": [
                                                            {
                                                              "src": url,
                                                            }
                                                        ]
                                                    }
                                                });
                                            }
                                        },error:function(res){
                                            if(res.status==404){
                                                layer.alert('图片资源无效', {
                                                    icon: 5,
                                                    shadeClose: true,
                                                });
                                            }
                                        }
                                    });
                                });
                            });
                        },500);

                        //处理操作列弹出窗口data-index
                        setTimeout(function(){
                            $('tr[data-index]').mouseenter(function(){
                                table_self_data_index = $(this).attr("data-index");
                                setTimeout(function(){
                                    $(".layui-table-grid-down").click(function(){
                                        setTimeout(function(){
                                            $(".layui-table-tips-main").attr("data-index",table_self_data_index);
                                        },50);
                                    });
                                },50);
                            })
                        },50);

                        autoFixedHeight();
                    }
                });

                try {
                    initializeSelect2();
                } catch (e) {

                }

                //排序事件
                table.on('sort({$this->form->tableId})', function(obj){
                    var where = obj.config.where;
                    where['sort'] = obj.field+' '+obj.type;
                    where['page'] = 1;
                    layui.data('sort',obj.field+' '+obj.type);

                    table.reloadData('{$this->form->tableId}', {
                        initSort: obj, // 记录初始排序，如果不设的话，将无法标记表头的排序状态。
                        where: where
                    });
                });

                //工具栏事件
                table.on('toolbar({$this->form->tableId})', function(obj){
                    var id = obj.config.id;
                    var checkStatus = table.checkStatus(id);
                    var othis = lay(this);
                    switch(obj.event){
                        case 'EXPORT':
                            window.export_status = 0;
                            var content = '';
                            content+='<div style="padding:10px 20px;width:100%;text-align:center;">选择需要导出的格式</div>';
                            content+='<div style="padding:10px 20px;" id="export_progress_box"></div>';
                            content+='<div style="display:none;text-align:center;" id="export_url"><a href="" style="color:#000000;" target="_blank">下载文件</a></div>';
                            content+='<div style="padding:10px 20px;text-align:center;">';
                            content+='<button type="button" class="layui-btn layui-bg-blue layui-btn-radius" id="export_excel_btn">excel</button>';
                            content+='<button type="button" class="layui-btn layui-bg-orange layui-btn-radius" id="export_csv_btn">csv</button>';
                            content+='</div>';
                            window.export_window = layer.open({
                                type: 1, // page 层类型
                                area: ['300px', '230px'],
                                title: '导出',
                                shade: 0.6, // 遮罩透明度
                                shadeClose: false, // 点击遮罩区域，关闭弹层
                                maxmin: false, // 允许全屏最小化
                                anim: 0, // 0-6 的动画形式，-1 不开启
                                content: content,
                                cancel:function(){
                                    window.export_status = 0;
                                }
                            });
                            setTimeout(function(){
                                var layui$ = layui.$;
                                // 动态插入进度条元素
                                layui$('#export_progress_box').html(`
                                    <div class="layui-progress layui-progress-big" lay-showPercent="true" lay-filter="export-filter-progress">
                                      <div class="layui-progress-bar layui-bg-blue" lay-percent="0%"></div>
                                    </div>
                                `);
                                // 渲染进度条组件
                                layui.element.render('progress', 'export-filter-progress');

                                //导出excel事件
                                $("#export_excel_btn").click(function(){
                                    if(window.export_status==1){
                                        return false;
                                    }
                                    $("#export_excel_btn").addClass("layui-btn-disabled");
                                    tableExport('excel',1);
                                });

                                //导出csv事件
                                $("#export_csv_btn").click(function(){
                                    if(window.export_status==1){
                                        return false;
                                    }
                                    $("#export_csv_btn").addClass("layui-btn-disabled");
                                    tableExport('csv',1);
                                });
                            },10);
                        break;

                        case 'IMPORT':
                            layer.open({
                                type: 2, // page 层类型
                                area: ['300px', '260px'],
                                title: '导入',
                                shade: 0.6, // 遮罩透明度
                                shadeClose: false, // 点击遮罩区域，关闭弹层
                                maxmin: false, // 允许全屏最小化
                                anim: 0, // 0-6 的动画形式，-1 不开启
                                content: "{$import_url}"
                            });
                        break;
EOT;
        foreach ($this->form->customerToolbars as $ct => $ctv) {
            $this->script .= <<<EOT

                        case '{$ctv['layEvent']}':
                            {$ctv['function']}
                        break;

EOT;
        }

        $switchBtnText = json_encode($this->form->switchBtnText);
        $this->script .= <<<EOT
                    };
                });
            });
            //格式化表格字段编辑组件
            function templetFormatterInput(val,newVal,row){
                var cols = {$cols};
                //格式化字段为文本框或者其他组件
                if(row.hasOwnProperty("LAY_COL")){
                    var obj = null;
                    var editType = null;
                    cols.map(rowitem=>{
                        rowitem.map(colitem=>{
                            if(colitem.field==row.LAY_COL.field && row.LAY_COL.field.indexOf(".") < 0){
                                obj = colitem;
                                editType = colitem.editType;
                            }
                        });
                    });
                    var noEditPrimarykeys = {$noEditPrimarykeys};
                    //如果编辑类型为多选，或者单选，处理下值放到newVal
                    if(editType!=undefined && ["checkbox","radio"].includes(editType)){
                        var vals = val.split(",");
                        var values = [];
                        vals.map((item,index)=>{
                            if(obj.options.hasOwnProperty(item)){
                                vals[index] = obj.options[item];
                            }
                        });
                        newVal = vals.join(",");
                    }

                    //如果是图片
                    if(obj && obj.hasOwnProperty('form_type') && obj.form_type=='image'){
                        if(val){
                            newVal="<img style='height: "+obj.thumbHeight+"px; width: "+obj.thumbWidth+"px;' class='preview-img' data-src='"+val+"' src='"+val+"'>";
                        }else{
                            newVal = '无';
                        }
                        editType = undefined;
                    }

                    //如果是开关，并且编辑类型为空
                    if(obj && obj.hasOwnProperty('form_type') && obj.form_type=='switchBtn'){
                        var switch_text = {$switchBtnText};
                        newVal = newVal?switch_text[0]:switch_text[1];
                    }

                    //如果当前字段是禁止编辑的，那么就返回newVal的值显示
                    if(editType!='image' && noEditPrimarykeys.length>0 && (noEditPrimarykeys.includes(row['{$this->form->parent->pk}']) || noEditPrimarykeys.includes(row['{$this->form->parent->pk}'].toString()))){
                        return newVal;
                    }
                    //如果当前字段可编辑，并且设置了编辑类型

                    if(editType!=undefined){

                        switch(editType){
                            case "textarea":
                                val = "<textarea type=\"text\" class=\"form-control\" onchange=\"{$this->form->tableId}_field_autopost(\'"+editType+"\',\'"+row.{$this->form->parent->pk}+"\',\'"+row.LAY_COL.field+"\',this)\" style=\"height:100%;width:100%;\">"+val+"</textarea>"
                            break;

                            case "switchBtn":
                                val = "<font onclick=\"{$this->form->tableId}_field_autopost(\'"+editType+"\',\'"+row.{$this->form->parent->pk}+"\',\'"+row.LAY_COL.field+"\',this)\">"
                                            +"<input type=\"checkbox\" lay-skin=\"switch\" value=\"1\" "+((val==1 ? ' checked' : ''))+"/>"
                                        +"</font>";
                            break;

                            case "checkbox":
                                var res = '';
                                var checks = val.split(",");
                                Object.keys(obj.options).forEach(function (key) {
                                    res += "<label style=\"float:left;margin:2px;\" onclick=\"{$this->form->tableId}_field_autopost(\'"+editType+"\',\'"+row.{$this->form->parent->pk}+"\',\'"+row.LAY_COL.field+"\',this)\">"
                                                +"<input type=\"checkbox\" title=\""+obj.options[key]+"\" lay-skin=\"checkbox\" value=\""+key+"\" "+((checks.includes(key) ? ' checked' : ''))+"/>"
                                            +"</label>";
                                });
                                val = res;
                            break;

                            case "radio":
                                var res = '';
                                Object.keys(obj.options).forEach(function (key) {
                                    res += "<label style=\"float:left;margin:2px;\" onclick=\"{$this->form->tableId}_field_autopost(\'"+editType+"\',\'"+row.{$this->form->parent->pk}+"\',\'"+row.LAY_COL.field+"\',this)\">"
                                                +"<input type=\"radio\" class=\"form-control\" value=\""+key+"\" "+((val==key ? ' checked' : ''))+" name=\""+obj.field+"__"+row.{$this->form->parent->pk}+"\"/>"+obj.options[key]
                                            +"</label>";
                                });
                                val = res;
                            break;

                            default :
                                val = "<input type=\""+editType+"\" class=\"form-control\" onchange=\"{$this->form->tableId}_field_autopost(\'"+editType+"\',\'"+row.{$this->form->parent->pk}+"\',\'"+row.LAY_COL.field+"\',this)\" value=\""+val+"\" style=\"max-height:100%;width:100%;\"/>"
                            break;
                        }
                    }else{
                        return newVal;
                    }
                }else{
                    return newVal;
                }
                return val;
            }
            //表格编辑自动提交
            function {$this->form->tableId}_field_autopost(editType,pk,field,that){
                var value = '';
                if(editType=='switchBtn'){
                    if($(that).prop("outerHTML").indexOf("onswitch")>-1){
                        value = 1;
                    }else{
                        value = 0;
                    }
                }else if(editType=='checkbox'){
                    var vals = [];
                    $(that).parent().parent().find('input[type=\"checkbox\"]:checked').each(function(index){
                        vals.push($(this).val());
                    });
                    value = vals.join(",");
                }else if(editType=='radio'){
                    value = $(that).parent().parent().find('input[type=\"radio\"]:checked').val();
                }else{
                    value = $(that).val();
                }

                var data = {
                    {$this->form->parent->pk}:pk,
                    [field]:value
                };
                window.loading  = layer.load(2,{shade:0.5});
                $.ajax({
                    type:'POST',
                    url:'{$autopost_url}',
                    data:data,
                    dataType:'json',
                    success:function(res) {
                        layer.close(window.loading);
                        if(res.hasOwnProperty("code") && res.code==1){
                            layer.alert(res.msg, {
                                icon: 6,
                                shadeClose: true,
                            });
                            layui.{$this->form->tableType}.reloadData('{$this->form->tableId}');
                        }else{
                            layer.alert(res.hasOwnProperty('msg') && res.msg?res.msg:'操作失败！', {
                                icon: 5,
                                shadeClose: true,
                            });
                        }
                    },
                    error:function(res){
                        layer.close(window.loading);
                        layer.alert(JSON.stringify(res), {
                            icon: 5,
                            shadeClose: true,
                        });
                    }
                });
            }

            // 导出
            // type：excel,csv
            // page: 1，第一次点击必须是1
            function tableExport(type,page){
                if(page==1){
                    layui.element.progress('export-filter-progress', '0%');
                    window.export_status = 1;
                    $("#export_url a").attr("href","");
                    $("#export_url").hide();
                }
                var sort = layui.data('sort');
                try{
                    var where = getSearchParams();
                }catch(e){
                    var where = {};
                }
                var noSelectFields = [];
                var datas = layui.data('{$this->form->tableId}-filter');
                Object.keys(datas).forEach(i => {
                    if(datas[i]==true){
                        noSelectFields.push(i);
                    }
                })
                $.ajax({
                    type:'POST',
                    url:'{$export_url}',
                    data:{
                        page:page,
                        type:type,
                        sort:sort,
                        no_select_fields:noSelectFields,
                        ...where
                    },
                    dataType:'json',
                    success:function(res) {
                        //设置进度
                        if(res.hasOwnProperty("code") && res.code==1){
                            layui.element.progress('export-filter-progress', res.data.progress+'%');
                            if(parseInt(page)<res.data.pages){
                                tableExport(type,parseInt(page)+1);
                            }else{
                                if(res.data.progress>=100){
                                    if(type=='excel'){
                                        $("#export_excel_btn").removeClass("layui-btn-disabled");
                                    }else{
                                        $("#export_csv_btn").removeClass("layui-btn-disabled");
                                    }
                                    window.export_status = 0;
                                    $("#export_url a").attr("href",res.data.url);
                                    $("#export_url").show();
                                }
                            }
                        }else{
                            layer.close(window.export_window);
                            layer.alert(res.hasOwnProperty('msg') && res.msg?res.msg:'操作失败！', {
                                icon: 5,
                                shadeClose: true,
                            });
                        }
                    },
                    error:function(res){
                        layer.close(window.export_window);
                        layer.alert(JSON.stringify(res), {
                            icon: 5,
                            shadeClose: true,
                        });
                    }
                });
            }


        </script>
EOT;

        $this->html .= '<link rel="stylesheet" href="/static/assets/admin/js/bootstrap-table/bootstrap-table.min.css">';
        $this->html .= '<link rel="stylesheet" href="/static/assets/admin/js/bootstrap-table/extensions/fixed-columns/bootstrap-table-fixed-columns.min.css">';

        $this->html .= '<script src="/static/assets/admin/js/bootstrap-table/bootstrap-table.js"></script>';
        $this->html .= '<script src="/static/assets/admin/js/bootstrap-table/locale/bootstrap-table-zh-CN.min.js"></script>';
        $this->html .= '<script src="/static/assets/admin/js/bootstrap-table/extensions/fixed-columns/bootstrap-table-fixed-columns.min.js"></script>';

        $this->html .= <<< EOT
            {$input_html}
EOT;
        // $content = $this->renderLeftTree($this->html, $this->script);
        $result = ['html' => $this->html, 'script' => $this->script];
        return $result;
    }

    /**
     * 渲染左边树形
     * @Author   July
     * @DateTime 2023-10-11T19:51:43+0800
     * @param    string                   $table_html   表格html
     * @return   string                   $content
     */
    public function renderLeftTree($table_html)
    {
        $content     = '';
        $tree_render = $this->form->leftTree->render();

        $content .= <<<EOT

<div class="main-layout row">
    <div class="main-layout-left col-3 col-sm-auto col-md-3 col-lg-3 col-xl-3 col-xxl-2">
        <div class="chevron-toggle mdi mdi-arrow-collapse-horizontal"></div>
        <div class="card h-100 border-0 shadow-sm">
EOT;
        if ($this->form->leftTree->tree->title) {
            $content .= <<<EOT

            <div class="card-header">
            {$this->form->leftTree->tree->title}
            </div>

EOT;
        }
        $content .= <<<EOT
            <div class="card-body" id="left-scroll-body">
                {$tree_render['html']}
                {$tree_render['script']}
            </div>
        </div>
    </div>
    <div class="main-layout-right col-12 col-sm-12 col-md-9 col-lg-9 col-xl-9 col-xxl-10">
        <div class="card" style="padding-top:0px;margin-bottom:0px;">
            <header class="card-header">
                <div class="card-title">{$this->form->tableTitle}</div>
            </header>
            <div class="card-body">
                {$table_html}
            </div>
        </div>
    </div>
</div>

EOT;

        return $content;
    }
}
